home *** CD-ROM | disk | FTP | other *** search
-
- TP&Asm Integrated Compile-Time Assembler Version 2.2
-
- Copyright (c) 1989 Richard W. Prescott
- All Rights Reserved
-
- ═══════ Built-In Assembly Language Support for Turbo Pascal Compilers ═══════
-
- All brand and product names mentioned herein are trademarks or registered
- trademarks of their respective holders.
-
- ┌─────────────────────────────────────────────────────────────────────┐
- │ This file contains detailed reference information to enable you to │
- │ make effective use of the TP&Asm assembly environment. For general │
- │ information on getting started please see the README file. │
- └─────────────────────────────────────────────────────────────────────┘
-
- This file contains information specific to the use of TP&Asm with
- Turbo Pascal 5.5 Objects and Methods. It is intended to supplement
- the information contained in the files TP&ASM.REF and TP&ASM2.REF.
-
-
- Turbo Pascal Version 5.5 extends Turbo Pascal through the addition
- of the Object Oriented Programming (OOP) concepts of "Objects" and
- "Methods". Briefly, an "Object" is a structured type which extends
- the concept of a Record, while a "Method" is a procedure or function
- which is associated with an Object in somewhat the same way as data
- components are associated with Records. It is assumed that the reader
- is familiar with these concepts and has read Chapter 1 of the Version
- 5.5 OOP Guide.
-
- Please keep in mind the following distinctions:
-
- Objects can be STATIC or DYNAMIC;
- according to whether they are statically defined in a VAR
- or CONST statement, or dynamically allocated on the Heap;
-
- Methods can be STATIC or VIRTUAL;
- according to whether they are defined "virtual", and
- thereby given an entry in a special structure called
- the Virtual Method Table (VMT);
-
- Method CALLs can be DIRECT or VIRTUAL;
- according to whether the target address of the call is
- "bound" into a direct call at compile time, or obtained
- from a lookup in the Virtual Method Table at run time.
-
- A Virtual method call is actually a standard Far Indirect Call in
- which the DWORD (Pointer) address of the method entry code is found
- in the Virtual Method Table. It is also possible to make indirect
- calls via a standard Pascal Pointer or assembly DWord variable, and
- the address to be loaded into the pointer can either be bound at
- compile time or obtained from the VMT mechanism.
-
- Note that in both Pascal and assembly language it is possible to
- make DIRECT calls to VIRTUAL methods.
-
-
-
- The following topics are described below:
-
- 1. Using Assembly Language in Methods
- 2. Accessing the Self parameter
- 3. Accessing Object data fields
- 4. Calling an Object's Methods
- 5. TypeOf and SizeOf for an Instance
-
-
-
- 1. Using Assembly Language in Methods
-
- Version 5.5 permits Methods to be written either entirely in Pascal
- or entirely in (External) Assembly language. TP&Asm provides the
- option of writing any portion of a Method in assembly language,
- using the TP&Asm "Assemble" statement. (A method, procedure, or
- function can have any number of Assemble statements).
-
- TP&Asm also provides the "Internal" statement, which can be used to
- write an entire method in assembly using standard External Assembly
- language format. This section provides examples using the Assemble
- and the Internal statements to implement an entire method in
- assembly language.
-
- As a simple example, consider the implementation of an "Area" method
- for the Rect object defined on page 103 of the OOP Guide. The Rect
- data fields are defined to be:
-
- X1, Y1, X2, Y2: Integer;
-
- where (X1,Y1) is the upper left corner and (X2,Y2) is the lower right
- corner. The Pascal implementation of this method would simply be
-
- Function Rect.Area: Integer;
- BEGIN
- Area := (X2 - X1) * (Y2 - Y1);
- END;
-
- for which the compiler generates the following code:
-
- BEGIN
-
- 3F4B:0037 55 PUSH BP ;Standard Entry Code
- 3F4B:0038 89E5 MOV BP,SP
- 3F4B:003A B80200 MOV AX,0002
- 3F4B:003D 9A4402573F CALL 3F57:0244
- 3F4B:0042 83EC02 SUB SP,+02
- ----
- Area := (X2 - X1) * (Y2 - Y1);
-
- 3F4B:0045 C47E06 LES DI,[BP+06] ;Les Di,Self
- 3F4B:0048 26 ES:
- 3F4B:0049 8B4506 MOV AX,[DI+06] :Mov Ax,Es:[Di].Y2
- 3F4B:004C C47E06 LES DI,[BP+06] ;Les Di,Self
- 3F4B:004F 26 ES:
- 3F4B:0050 2B4502 SUB AX,[DI+02] ;Sub Ax,Es:[Di].Y1
- 3F4B:0053 8BD0 MOV DX,AX
- 3F4B:0055 C47E06 LES DI,[BP+06] ;Les Di,Self
- 3F4B:0058 26 ES:
- 3F4B:0059 8B4504 MOV AX,[DI+04] ;Mov Bx,Es:[Di].X2
- 3F4B:005C C47E06 LES DI,[BP+06] ;Les Di,Self
- 3F4B:005F 26 ES:
- 3F4B:0060 2B05 SUB AX,[DI] ;Sub Bx,Es:[Di].X1
- 3F4B:0062 F7EA IMUL DX ;IMul Dx
- 3F4B:0064 8946FE MOV [BP-02],AX ;Mov Area,Ax
- ----
- END;
-
- 3F4B:0067 8B46FE MOV AX,[BP-02] ;Standard Exit Code
- 3F4B:006A 89EC MOV SP,BP
- 3F4B:006C 5D POP BP
- 3F4B:006D CA0400 RETF 0004
- ----
-
-
- 1.1 Using an Assemble statement
-
- The following example illustrates how the "Area" method would be
- coded using an Assemble statement. Note that the fields of Rect
- are accessible by name without any explicit assembly definition
- (e.g. STRUC), and that since Es:Di is never altered, it is not
- necessary to reload it before each data access. Standard entry
- and exit code is provided by the compiler.
-
-
- Function Rect.Area: Integer;
- BEGIN {- Compiler generates standard entry code -}
- Assemble
- Les Di,Self ;Load Self Pointer
- Mov Ax,Es:[Di].Y2
- Sub Ax,Es:[Di].Y1 ;Compute Y2 - Y1
- Mov Dx,Es:[Di].X2
- Sub Dx,Es:[Di].X1 ;Compute X2 - X1
- IMul Dx ;Compute product
- Mov Area,Ax ;put in function result
- End; {Assemble}
- END; {- Compiler generates standard exit code -}
-
-
- 1.2 Using an Internal statement - External Assembly format
-
- The following example illustrates how the "Area" method would be
- coded using an Internal statement in the full External Assembly
- format. Note that the fields of Rect are again accessible by
- name without any explicit assembly definition. As with External
- assembly code, entry and exit code must be explicitly provided.
-
-
- Internal RectMethods
-
- CODE SEGMENT BYTE PUBLIC
-
- ASSUME Cs:CODE
-
- PUBLIC Rect@Area
-
- Rect@Area PROC FAR
-
- @Self EQU DWORD PTR [bp+6]
-
- Push Bp ;Explicit
- Mov Bp,Sp ; Entry Code
-
- Les Di,@Self ;Load Self Pointer
- Mov Ax,Es:[Di].Y2
- Sub Ax,Es:[Di].Y1 ;Compute Y2 - Y1
- Mov Dx,Es:[Di].X2
- Sub Dx,Es:[Di].X1 ;Compute X2 - X1
- IMul Dx ;Compute product
-
- Mov Sp,Bp ;Explicit (Function
- Pop Bp ; Exit Result
- Retf 4 ; Code is in Ax)
-
- Rect@Area ENDP
-
- CODE ENDS
-
- END
-
-
- 1.3 Using an Internal statement - reduced overhead format
-
- TP&Asm ignores certain "overhead" statements including "Assume"
- and "Public", and can make its own determination of the proper PROC
- model to use. The following example illustrates how the "Area"
- method would be coded using an Internal statement with the minimum
- necessary "overhead" statements. Note that the more readable form
- "Rect.Area" is permitted in place of "Rect@Area".
-
-
- Internal RectMethods
- CODE SEGMENT
- Rect.Area PROC
- @Self EQU D[bp+6]
- Push Bp ;Explicit
- Mov Bp,Sp ; Entry Code
- Les Di,@Self ;Load Self Pointer
- Mov Ax,Es:[Di].Y2
- Sub Ax,Es:[Di].Y1 ;Compute Y2 - Y1
- Mov Dx,Es:[Di].X2
- Sub Dx,Es:[Di].X1 ;Compute X2 - X1
- IMul Dx ;Compute product
- Mov Sp,Bp ;Explicit (Function
- Pop Bp ; Exit Result
- Retf 4 ; Code is in Ax)
- Rect.Area ENDP
- CODE ENDS
- END
-
-
- 2. Accessing the Self parameter
-
- Every method has an implicit VAR parameter "Self" which possesses
- the type of the object whose method is being defined, and which
- contains the address of the instance which generated the method
- call. This parameter is always the last parameter pushed onto
- the stack, and is therefore always located immediately above the
- return address (Cs:Ip).
-
-
- 2.1 Accessing Self within an Assemble statement
-
- Within an Assemble statement the Self parameter to a method is
- accessible by name. The following statement loads the Self
- parameter into Es:Di
-
- Les Di,Self
-
- Since the Self parameter is a (DWord) Pointer, an attempt to
- reference it as a Byte or Word variable (e.g. "Mov Ax,Self")
- will generate a syntax error. You can override the defined
- type of any variable, however, using a data size specifier.
- Thus any of the following:
-
- Mov W Ax,Self
- Mov Ax,W Self
- Mov Ax,WORD PTR Self
-
- will load into Ax the OFFSET of the instance which generated
- the method call.
-
-
- 2.2 Accessing Self within an Internal statement
-
- Like External assembly code, Internal assembly code cannot
- reference parameters by name. References to the Self parameter
- must therefore be coded as explicit offsets to a properly
- initialized Base or Index register. The necessary offset will
- depend upon the register chosen.
-
- Assuming the following entry code:
-
- Push Bp
- Mov Bp,Sp
-
- then the Self parameter will be at [Bp+6], and the following
- statement will load it into Es:Di
-
- Les Di,[Bp+6]
-
- As an alternative, you can define Self with an EQUate so that
- subsequent statements can access it by name:
-
- Self EQU D [Bp+6]
- Les Di,Self
-
- (Since Bp references use Ss as the default segment it is not
- necessary to code an explicit Ss Override).
-
- It is also possible to access Self and other method parameters
- using another Index or Base register. Given the following entry
- code:
-
- Mov Bx,Sp
-
- then the Self parameter will be at Ss:[Bx+4], and the following
- statement will load it into Es:Di
-
- Les Di,Ss:[Bx+4]
-
- Again, you can define Self with an EQUate so that subsequent
- statements can access it by name:
-
- Self EQU D Ss:[Bx+4]
- Les Di,Self
-
- (Since Bx references use Ds as the default segment you must code
- an explicit Ss override).
-
-
-
- 3. Accessing Object data fields
-
- TP&Asm provides the capability of making assembly reference to
- Object data fields both from within and from outside its methods.
- The examples below assume the following VAR and Type Definitions:
-
- TYPE
- RecType = Record
- NestedInteger: Integer;
- NestedPointer: Pointer;
- End;
-
- ObjType = object
- ObjByte: Byte;
- ObjString: STRING[20];
- ObjRecord: RecType;
- :
- end;
-
- VAR
- StaticObjInst: ObjType;
- DynamicObjPtr: ^ObjType;
-
-
- 3.1 Accessing an Object's data fields from within its methods
-
- Within an object's methods the unqualified reference to an Object
- data field represents the offset of that field within the Object
- structure. Access to the Object's data is accomplished by loading
- the "Self" pointer into a Segment:Index register pair (typically
- Es:Di), and using the field identifier as the offset in an indexed
- memory reference:
-
- Les Di,Self
- Es Mov Al,ObjByte[Di]
- Es Lea Di,ObjString[Di]
- Es IMul ObjRecord.NestedInteger[Di]
- Es Les Bx,ObjRecord.NestedPointer[Di]
-
- TP&Asm supports numerous other formats for coding indexed memory
- access:
-
- Es Mov Al,[Di].ObjByte
- Es Mov Al,[Di+ObjByte]
- Mov Al,Es:ObjByte[Di]
- Mov Al,Es:[Di].ObjByte
- Mov Al,Es:[Di]ObjByte
- Mov Al,Es:[Di+ObjByte]
- Es:
- Mov Al,[Di+ObjByte]
-
- It is also possible to use a full TypeDef.Component specification
- as is done with Dynamic Object data references (see 3.3):
-
- Es Mov Al,ObjType.ObjByte[Di]
-
- Unindexed reference to an Object's data fields is not permitted
- unless qualified with the Object Type identifier, in which case
- the reference is treated as an immediate data operand equal to
- the offset of the field within the Object structure:
-
- Mov Ax,ObjType.ObjString ; Same as Mov Ax,0001
-
-
- 3.2 Accessing STATIC Object data fields from outside its methods
-
- Outside an object's methods all references to an Object's data
- fields must be qualified with either the Instance identifier or the
- Object's Type identifier. Access to a Static Object's data is
- accomplished using a fully qualified name beginning with the
- Instance identifier:
-
- Mov Al,StaticObjInst.ObjByte
- Lea Di,StaticObjInst.ObjString
- IMul StaticObjInst.ObjRecord.NestedInteger
- Les Bx,StaticObjInst.ObjRecord.NestedPointer
- Mov Dx,OFFSET StaticObjInst.ObjString
-
- Unless preceeded by the keyword "OFFSET", the reference refers
- to the contents of the indicated memory address, using the defined
- type of the particular Object field. (Note: OFFSET is not permitted
- with local variables, which are always referenced relative to [Bp].
- Use "Lea Reg,LocalVar" in place of "Mov Reg,OFFSET LocalVar").
-
- As noted above, if a reference is qualified with the Object Type
- identifier, it is treated as an immediate data operand equal to
- the offset of the field within the Object structure:
-
- Mov Ax,ObjType.ObjString ; Same as Mov Ax,0001
-
-
- 3.3 Accessing DYNAMIC Object data fields from outside its methods
-
- Access to a Dynamic Object's data is accomplished by loading the
- pointer variable into a Segment:Index register pair (typically Es:Di),
- and using the field identifier (qualified by the Object's Type
- identifier) as the offset in an indexed memory reference:
-
- Les Di,DynamicObjPtr
- Es Mov Al,ObjType.ObjByte[Di]
- Es Lea Di,ObjType.ObjString[Di]
- Es IMul ObjType.ObjRecord.NestedInteger[Di]
- Es Les Bx,ObjType.ObjRecord.NestedPointer[Di]
-
- An indexed reference as shown uses the defined type of the particular
- object field. An unindexed reference is treated as an immediate data
- operand equal to the offset of the field within the Object structure:
-
- Mov Ax,ObjType.ObjString ; Same as Mov Ax,0001
-
-
-
- 4. Calling an Object's Methods
-
- Outside an Object's methods, Pascal method calls are always direct
- if the method is static and virtual if the method is virtual.
- Within a method, the same strategy is used, except when the method
- call is qualified with the Object Type identifier of the current
- object or an ancestor. In this latter case a direct call is used
- even if the method is virtual.
-
- As shown in the examples below, TP&Asm provides the capability to
- exercise total control over the type of call to use both within and
- outside an Object's methods. It is not the presence or absence of
- an Object Type qualifier, however, which determines whether a
- virtual or direct call is used - in fact, all assembly language
- method calls from outside an object's methods must be qualified
- with the Object Type. It is the presence or absence of an explicit
- memory operand (typically an index register) which determines
- whether a virtual method identifier is interpreted as the method's
- offset within its VMT, or as the method's actual (static) address.
-
- The examples below assume that ObjType has the following Methods:
-
- PROCEDURE StaticMeth;
- PROCEDURE VirtualMeth; Virtual;
-
- It is also assumed that the following Instance and Pointer variable
- have been defined:
-
- VAR
- StaticObjInst: ObjType;
- DynamicObjPtr: ^ObjType;
-
-
- 4.1 Calling an Object's Methods from within another method
-
- Method calls made from within another method should first push
- any explicit parameters, and then push the current "Self" pointer
- as the Self parameter of the target method. Calls to static
- methods are always direct, and are made using an unindexed
- reference to the method identifier:
-
- Les Di,Self ;Load Self pointer
- Push Es,Di ;Push as Self parameter
- Call StaticMeth ;Unindexed reference codes direct call
-
- The method identifier is interpreted as the (static) address of the
- method code within the current CSeg. The following "Pas" statement
- is equivalent:
-
- Pas StaticMeth;
-
- Direct calls to Virtual methods are made using an unindexed
- reference to the method identifier:
-
- Les Di,Self ;Load Self pointer
- Push Es,Di ;Push as Self parameter
- Call VirtualMeth ;Unindexed reference codes direct call
-
- The method identifier is interpreted as the (static) address of the
- method code within the current CSeg. The following "Pas" statement
- is equivalent:
-
- Pas ObjType.VirtualMeth;
-
- Virtual calls to Virtual methods are made using an indexed
- reference to the method identifier, after first loading the DSeg
- offset of Self's VMT into the index register:
-
- Les Di,Self ;Load Self pointer
- Push Es,Di ;Push as Self parameter
- Es Mov Di,VMT[Di] ;Load VMT offset into Di
- Call VirtualMeth[Di] ;Indexed reference codes virtual call
-
- The method identifier is interpreted as the offset within the VMT of
- the method's VMT entry. The following "Pas" statement is equivalent:
-
- Pas VirtualMeth;
-
-
-
- 4.2 Calling a STATIC Object's Methods from outside its methods
-
- Method calls made from outside a STATIC Object's methods should
- first push any explicit parameters, and then push the static
- address of the current instance as the Self parameter of the
- target method. All method identifiers and all references to the
- symbol "VMT" must be qualified with an Object Type identifier.
-
- Calls to static methods are always direct, and are made using an
- unindexed reference to the method identifier:
-
- Lea Di,StaticObjInst ;Load offset of Instance into Di
- Push Ds,Di ;Push Ss,Di for a Local Var Instance
- Call ObjType.StaticMeth ;Unindexed ref codes direct call
-
- The method identifier is interpreted as the (static) address of the
- method code within the current CSeg. The following "Pas" statement
- is equivalent:
-
- Pas StaticObjInst.StaticMeth;
-
- Direct calls to Virtual methods are made using an unindexed
- reference to the method identifier:
-
- Lea Di,StaticObjInst ;Load offset of Instance into Di
- Push Ds,Di ;Push Ss,Di for a Local Var Instance
- Call ObjType.VirtualMeth ;Unindexed ref codes direct call
-
- The method identifier is interpreted as the (static) address of
- the method code within the current CSeg. There is no Pascal
- equivalent.
-
- Virtual calls to Virtual methods are made using an indexed
- reference to the method identifier, after first loading the DSeg
- offset of the Object Type's VMT into the index register:
-
- Lea Di,StaticObjInst ;Load offset of Instance into Di
- Push Ds,Di ;Push Ss,Di for a Local Var Instance
- Mov Di,ObjType.VMT[Di] ;Load VMT offset into Di
- Call ObjType.VirtualMeth[Di] ;Indexed ref codes virtual call
-
- The method identifier is interpreted as the offset within the VMT of
- the method's VMT entry. The following "Pas" statement is equivalent:
-
- Pas StaticObjInst.VirtualMeth;
-
-
- 4.3 Calling a DYNAMIC Object's Methods from outside its methods
-
- Method calls made from outside a DYNAMIC Object's methods should
- first push any explicit parameters, and then push the dynamic
- pointer variable for the current instance as the Self parameter
- of the target method. All method identifiers and all references
- to the symbol "VMT" must be qualified with an Object Type
- identifier.
-
- Calls to static methods are always direct, and are made using an
- unindexed reference to the method identifier:
-
- Les Di,DynamicObjPtr ;Load Pointer into Es:Di
- Push Es,Di ;Push as "Self" parameter
- Call ObjType.StaticMeth ;Unindexed ref codes direct call
-
- The method identifier is interpreted as the (static) address of the
- method code within the current CSeg. The following "Pas" statement
- is equivalent:
-
- Pas DynamicObjPtr^.StaticMeth;
-
- Direct calls to Virtual methods are made using an unindexed
- reference to the method identifier:
-
- Les Di,DynamicObjPtr ;Load Pointer into Es:Di
- Push Es,Di ;Push as "Self" parameter
- Call ObjType.VirtualMeth ;Unindexed ref codes direct call
-
- The method identifier is interpreted as the (static) address of
- the method code within the current CSeg. There is no Pascal
- equivalent.
-
- Virtual calls to Virtual methods are made using an indexed
- reference to the method identifier, after first loading the DSeg
- offset of the Object Type's VMT into the index register:
-
- Les Di,DynamicObjPtr ;Load Pointer into Es:Di
- Push Es,Di ;Push as "Self" parameter
- Mov Di,ObjType.VMT[Di] ;Load VMT offset into Di
- Call ObjType.VirtualMeth[Di] ;Indexed ref codes virtual call
-
- The method identifier is interpreted as the offset within the VMT of
- the method's VMT entry. The following "Pas" statement is equivalent:
-
- Pas DynamicObjPtr^.VirtualMeth;
-
-
-
- 5. TypeOf and SizeOf for an Instance
-
-
- 5.1 TypeOf and SizeOf within a method
-
- The following code will set Dx:Ax to TypeOf(Self)
-
- Les Di,Self
- Es Mov Ax,ObjType.VMT[Di]
- Mov Dx,Ds
-
- The following code will set Ax to SizeOf(Self)
-
- Les Di,Self
- Es Mov Di,ObjType.VMT[Di]
- Mov Ax,[Di]
-
-
- 5.2 TypeOf and SizeOf for a STATIC Object instance
-
- The following code will set Dx:Ax to TypeOf(StaticObjInst)
-
- Lea Di,StaticObjInst
- Mov Ax,ObjType.VMT[Di]
- Mov Dx,Ds
-
- The following code will set Ax to SizeOf(StaticObjInst)
-
- Lea Di,StaticObjInst
- Mov Di,ObjType.VMT[Di]
- Mov Ax,[Di]
-
-
-
- 5.3 TypeOf and SizeOf for a DYNAMIC Object instance
-
- The following code will set Dx:Ax to TypeOf(DynamicObjPtr^)
-
- Les Di,DynamicObjPtr
- Es Mov Ax,ObjType.VMT[Di]
- Mov Dx,Ds
-
- The following code will set Dx:Ax to SizeOf(DynamicObjPtr^)
-
- Les Di,DynamicObjPtr
- Es Mov Di,ObjType.VMT[Di]
- Mov Ax,[Di]
-
-